package cn.blnp.net.flowable.task.ext.shell;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.map.MapUtil;
import lombok.extern.slf4j.Slf4j;
import org.flowable.engine.HistoryService;
import org.flowable.engine.RepositoryService;
import org.flowable.engine.RuntimeService;
import org.flowable.engine.TaskService;
import org.flowable.engine.history.HistoricProcessInstance;
import org.flowable.engine.repository.Deployment;
import org.flowable.engine.repository.ProcessDefinition;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.task.api.Task;
import org.flowable.task.api.TaskQuery;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;

import javax.annotation.Resource;
import java.util.HashMap;
import java.util.Map;

/**
 * <h3></h3>
 *
 * @author <a href="mailto:blnp.yibin@qq.com">lyb</a>
 * @version 1.0
 * @since 2025/5/15 10:06
 */
@Slf4j
@SpringBootTest
public class ShellTaskTest {

    @Resource
    private RepositoryService repositoryService;
    @Resource
    private RuntimeService runtimeService;
    @Resource
    private TaskService taskService;
    @Resource
    private HistoryService historyService;

    /**
     *  <h2>Shell任务案例</h2>
     *  <hr/>
     *  <p>
     *      Shell任务可以在流程执行过程中运行Shell脚本与命令。需要注意的是，Shell任务并非BPMN 2.0规范定义的“官方”任务。在Flowable中，Shell任务作为一种特殊服务任务实现。
     *   事件定义格式如下所示：
     *   <pre>
     *       {@code
     *          <serviceTask id="shellTask1" name="Shell任务" flowable:type="shell" />
     *       }
     *   </pre>
     *   Shell任务可以通过属性注入的方式配置各种属性，这些属性的值可以是UEL表达式，在流程执行时解析。Shell任务可配置属性如下所示：
     *   <<ol>
     *       <li>
     *           command 属性：
     *           <ul>
     *               <li><b>类型：</b>String</li>
     *               <li><b>默认值：</b></li>
     *               <li><b>描述：</b>要执行的Shell命令</li>
     *           </ul>
     *       </li>
     *       <li>
     *           arg1～arg5 配置属性：
     *           <ul>
     *               <li><b>类型：</b>String</li>
     *               <li><b>默认值：</b></li>
     *               <li><b>描述：</b>参数，限制为5个。运行时多个参数之间用空格分隔</li>
     *           </ul>
     *       </li>
     *       <li>
     *           wait 属性：
     *           <ul>
     *               <li><b>类型：</b>boolean</li>
     *               <li><b>默认值：</b>true</li>
     *               <li><b>描述：</b>是否要等待Shell进程终止</li>
     *           </ul>
     *       </li>
     *       <li>
     *           redirectError 属性：
     *           <ul>
     *               <li><b>类型：</b>boolean</li>
     *               <li><b>默认值：</b>false</li>
     *               <li><b>描述：</b>是否把错误信息输出到标准输出流中</li>
     *           </ul>
     *       </li>
     *       <li>
     *           <ul>
     *               <li><b>类型：</b></li>
     *               <li><b>默认值：</b></li>
     *               <li><b>描述：</b></li>
     *           </ul>
     *       </li>
     *       <li>
     *           cleanEnv 属性：
     *           <ul>
     *               <li><b>类型：</b>boolean</li>
     *               <li><b>默认值：</b>false</li>
     *               <li><b>描述：</b>Shell进程是否继承当前环境</li>
     *           </ul>
     *       </li>
     *       <li>
     *           outputVariable 配置：
     *           <ul>
     *               <li><b>类型：</b>String</li>
     *               <li><b>默认值：</b></li>
     *               <li><b>描述：</b>保存输出的变量名</li>
     *           </ul>
     *       </li>
     *       <li>
     *           errorCodeVariable 配置：
     *           <ul>
     *               <li><b>类型：</b>String</li>
     *               <li><b>默认值：</b></li>
     *               <li><b>描述：</b>保存结果错误码的变量名</li>
     *           </ul>
     *       </li>
     *        <li>
     *            directory 配置：
     *            <ul>
     *                <li><b>类型：</b>String</li>
     *                <li><b>默认值：</b>当前目录</li>
     *                <li><b>描述：</b>执行命令、脚本的目录</li>
     *            </ul>
     *        </li>
     *   </ol>
     *  </p>
     **/
    @Test
    public void testBase() {

    }

    /**
     *  <h2>流程演示</h2>
     *  <hr/>
     *  <p>
     *      该流程根据用户提交的浏览器路径和网页URL，由ShellTask执行Shell命令启动浏览器并访问该网页。<br/>
     *      <b>流程定义文件：</b>{@link flow/shellTaskProcess.bpmn20.xml}<br/>
     *      <b>流程预览图：</b><br/>
     *      <img src="https://cdn4.winhlb.com/2025/05/15/68255232d7417.png" />
     *  </p>
     **/
    @Test
    public void testExample() {
        Deployment deploy = repositoryService.createDeployment()
                .name("Shell任务演示案例")
                .addClasspathResource("flow/shellTaskProcess.bpmn20.xml")
                .deploy();
        log.info("部署流程定义：{}", deploy.getId());
        ProcessDefinition procDef = repositoryService.createProcessDefinitionQuery()
                .deploymentId(deploy.getId())
                .singleResult();
        log.info("流程定义编号：{}", procDef.getId());
        //启动流程实例
        ProcessInstance procInst = runtimeService.startProcessInstanceById(procDef.getId());
        TaskQuery taskQuery = taskService.createTaskQuery()
                .processInstanceId(procInst.getId());

        //查询并完成第一个任务
        Task firstTask = taskQuery.singleResult();
        //设置流程变量
        Map<String, Object> varMap = MapUtil.builder(new HashMap<String, Object>())
                .put("browserLocation", "C:\\Program Files (x86)\\Microsoft\\Edge\\Application\\msedge.exe")
                .put("webUrl", "https://blog.csdn.net/qq_37165235?spm=1000.2115.3001.10640")
                .build();
        taskService.complete(firstTask.getId(), varMap);

        //查询历史流程实例
        HistoricProcessInstance hisProcInst = historyService
                .createHistoricProcessInstanceQuery()
                .processInstanceId(procInst.getId())
                .singleResult();
        if (hisProcInst.getEndTime() != null) {
            log.info("当前流程已结束，结束时间：{}", DateUtil.formatDateTime(hisProcInst.getEndTime()));
        }

        /**
         *  演示结果：
         * 2025-05-15 10:37:23.543  INFO 5932 --- [           main] c.b.n.f.task.ext.shell.ShellTaskTest     : 部署流程定义：87d18be2-3135-11f0-be81-50ebf6ec8f6d
         * 2025-05-15 10:37:23.547  INFO 5932 --- [           main] c.b.n.f.task.ext.shell.ShellTaskTest     : 流程定义编号：shellTaskProcess:2:881dfe35-3135-11f0-be81-50ebf6ec8f6d
         * 2025-05-15 10:37:23.791  INFO 5932 --- [           main] c.b.n.f.task.ext.shell.ShellTaskTest     : 当前流程已结束，结束时间：2025-05-15 10:37:23
         **/
    }
}
